//=============================================================================
/**
 * @file	ground_anime.c
 * @brief	地形アニメーション関連処理
 * @author	Nozomu Saito
 *
 */
//=============================================================================
#include "common.h"
#include "ground_anime.h"
#include "system/arc_tool.h"

static void CSTM_NNS_G3dAnmObjInit(NNSG3dAnmObj* pAnmObj, void* pResAnm);
static void CSTM_NNSi_G3dAnmObjInitNsBta(NNSG3dAnmObj* pAnmObj, void* pResAnm);
static NNSG3dAnmObj* CSTM_NNS_G3dAllocAnmObj(NNSFndAllocator* pAlloc, const void* pAnm);
static u32 CSTM_NNS_G3dAnmObjCalcSizeRequired( const void* pAnm );

static void SetUpFunc(	NNSFndAllocator *pAllocator,
						NNSG3dAnmObj** pAnmObj,
						void *mem,
						G3D_ANM_CUSTOM_WORK_PTR pCustomWork	);

typedef struct GROUND_ANIME_MANAGER_tag
{
	G3D_ANM_MNG_PTR MngPtr;
	G3D_ANM_DATA_PTR AnmPtr;
}GROUND_ANIME_MANAGER;


//==============================================================================
/**
 * 地形アニメ初期化
 *
 * @param   pMngLstPtr	アニメマネージャリストポインタ
 *
 * @retval  ptr			地形アニメマネージャポインタ
 */
//==============================================================================
GROUND_ANIME_MNG_PTR GrndAnm_Init(G3D_ANM_MNG_LST_PTR pMngLstPtr)
{
	GROUND_ANIME_MNG_PTR ptr;
	ptr = sys_AllocMemory(HEAPID_FIELD, sizeof(GROUND_ANIME_MANAGER));
	ptr->MngPtr = G3dAnime_CreateManager( pMngLstPtr, HEAPID_FIELD, 1 );
	//カスタムセットアップ関数を設定
	G3dAnime_SetCustomFunc(ptr->MngPtr, SetUpFunc);

	return ptr;
}

//==============================================================================
/**
 * 地形アニメ終了
 * G3dAnime_CreateManagerで確保したマネージャ自体は、アニメマネージャが解放してくれるので、
 * ここでは、地形アニメマネージャを解放するのみとする
 *
 * @param   pGrndAnmMngPtr	地形アニメマネージャポインタ
 *
 * @retval  none
 */
//==============================================================================
void GrndAnm_End(GROUND_ANIME_MNG_PTR pGrndAnmMngPtr)
{
	sys_FreeMemoryEz(pGrndAnmMngPtr);
}

//==============================================================================
/**
 * 地形アニメセットアップ
 *
 * @param	pGrndAnmMngPtr	地形アニメマネージャポインタ
 * @param   iAnmIdx			地形アニメインデックス
 *
 * @retval  none
 */
//==============================================================================
void GrndAnm_Setup(GROUND_ANIME_MNG_PTR pGrndAnmMngPtr, const int inAnmIdx)
{
	void *pAnmRes;
	void *mem;
	G3D_ANM_DATA_PTR g3d_data;
	g3d_data = G3dAnime_PopAnmData( pGrndAnmMngPtr->MngPtr );
	GF_ASSERT(g3d_data != NULL);
	G3dAnimeData_Entry(g3d_data, LOOP_INFINIT, FALSE, FALSE);
	//アニメ初期化
	mem = ArchiveDataLoadMalloc(	ARC_GROUND_ANM,
									inAnmIdx,
									HEAPID_FIELD );

	G3dAnime_CustomSetup(pGrndAnmMngPtr->MngPtr, g3d_data, mem, NULL);

	pGrndAnmMngPtr->AnmPtr = g3d_data;

}

//==============================================================================
/**
 * 地形アニメのADD
 *
 * @param	pGrndAnmMngPtr	地形アニメマネージャポインタ
 * @param	pRenderObj		レンダーＯＢＪポインタ
 *
 * @retval  none
 */
//==============================================================================
void GrndAnm_AddAnm(GROUND_ANIME_MNG_PTR pGrndAnmMngPtr, NNSG3dRenderObj *pRenderObj)
{
	G3dAnimeData_Add(pRenderObj, pGrndAnmMngPtr->AnmPtr);
}

//==============================================================================
/**
 * 地形アニメのリムーブ
 *
 * @param	pGrndAnmMngPtr	地形アニメマネージャポインタ
 * @param	pRenderObj		レンダーＯＢＪポインタ
 *
 * @retval  none
 */
//==============================================================================
void GrndAnm_RemoveAnm(GROUND_ANIME_MNG_PTR pGrndAnmMngPtr, NNSG3dRenderObj *pRenderObj)
{
	G3dAnimeData_Remove(pRenderObj, pGrndAnmMngPtr->AnmPtr);
}

//==============================================================================
/**
 * 地形アニメの有無
 *
 * @param	pGrndAnmMngPtr	地形アニメマネージャポインタ
 *
 * @retval  u16				0以外:ある	0:ない
 */
//==============================================================================
u16 GrndAnm_IsValid(GROUND_ANIME_MNG_PTR pGrndAnmMngPtr)
{
	return G3dAnime_GetAnmStackNum(pGrndAnmMngPtr->MngPtr);
}

//==============================================================================
/**
 * 地形アニメセットアップ
 *
 * @param   *pAllocator	アロケータポインタ
 * @param	pAnmObj		アニメＯＢＪポインタのポインタ
 * @param	mem			メモリ
 * @param	pCustomWork	カスタムワーク
 *
 * @retval  none
 */
//==============================================================================
static void SetUpFunc(	NNSFndAllocator *pAllocator,
						NNSG3dAnmObj** pAnmObj,
						void *mem,
						G3D_ANM_CUSTOM_WORK_PTR pCustomWork	)
{
	void *pAnmRes;
	//アニメ初期化
	pAnmRes = NNS_G3dGetAnmByIdx(mem, 0);
	*pAnmObj = CSTM_NNS_G3dAllocAnmObj( pAllocator,// 使用するアロケータを指定
										pAnmRes);	 // アニメーションリソースを指定
	CSTM_NNS_G3dAnmObjInit(*pAnmObj,	// アニメーションオブジェクトへのポインタ
                          pAnmRes);		// アニメリソースへのポインタ

	//テスト
	OS_Printf("ANIME_FRAME::%d--------------------------------------\n",NNS_G3dAnmObjGetNumFrame(*pAnmObj));
}

#define _NNS_G3D_ANMOBJ_SIZE_MATANM(srtAnm) ((sizeof(NNSG3dAnmObj) + sizeof(u16) *  srtAnm->dict.numEntry) & ~3)

/*---------------------------------------------------------------------------*
    NNS_G3dAnmObjCalcSizeRequired

    アニメーションリソース、モデルリソースに対応するNNSG3dAnmObjに必要な
    メモリサイズを返します。

 * @param	pAnm			リソースデータ
 *
 * @retval  u32		サイズ
 *
 *---------------------------------------------------------------------------*/
static u32
CSTM_NNS_G3dAnmObjCalcSizeRequired(const void* pAnm )
{
	const NNSG3dResTexSRTAnm* srtAnm;
	srtAnm = (NNSG3dResTexSRTAnm*)pAnm;

	OS_Printf("anime_num = %d\n",srtAnm->dict.numEntry);

    return _NNS_G3D_ANMOBJ_SIZE_MATANM(srtAnm);
}


/*---------------------------------------------------------------------------*
    NNS_G3dAllocAnmObj

    NNSG3dAnmObjのための領域をヒープ領域から確保します。
    イニシャライズは別途NNS_G3dAnmObjInitで行ってください。

 * @param	pAlloc		アロケーター
 * @param	pAnm		リソースデータ
 *
 * @retval  NNSG3dAnmObj *
 *
 *---------------------------------------------------------------------------*/
static NNSG3dAnmObj*
CSTM_NNS_G3dAllocAnmObj(NNSFndAllocator* pAlloc,
                   const void* pAnm)
{
    u32 sz;
    sz = CSTM_NNS_G3dAnmObjCalcSizeRequired(pAnm);
    return (NNSG3dAnmObj*) NNS_FndAllocFromAllocator(pAlloc, sz);
}

/*---------------------------------------------------------------------------*
    NNSi_G3dAnmObjInitNsBta

    NNSG3dAnmObjを.nsbtaリソース用にイニシャライズします。
    NNS_G3dInitAnmObjから呼び出されます。

 * @param	pAnmObj		アニメＯＢＪポインタのポインタ
 * @param	pResAnm		アニメリソース
 *
 * @retval  none
 *
 *---------------------------------------------------------------------------*/
static void
CSTM_NNSi_G3dAnmObjInitNsBta(NNSG3dAnmObj* pAnmObj,
                        void* pResAnm)
{
    u32 i;
    NNSG3dResTexSRTAnm* srtAnm;

    srtAnm = (NNSG3dResTexSRTAnm*)pResAnm;
    pAnmObj->funcAnm = (void*) NNS_G3dFuncAnmMatNsBtaDefault;
    pAnmObj->numMapData = srtAnm->dict.numEntry;

    // まずはmapDataをゼロクリア
    MI_CpuClear16(&pAnmObj->mapData[0], sizeof(u16) * pAnmObj->numMapData);

	OS_Printf("地形アニメは全部で%d\n",srtAnm->dict.numEntry);

    for (i = 0; i < srtAnm->dict.numEntry; ++i)
    {
		const NNSG3dResName* name = NNS_G3dGetResNameByIdx(&srtAnm->dict, i);
		OS_Printf("Name = %s", name->name);
        // リソースID iに対応するリソースが存在する場合は、
        // マテリアルID idxにリソースID iを関連付ける。
        pAnmObj->mapData[i] = (u16)(i | NNS_G3D_ANMOBJ_MAPDATA_EXIST);
    }
}


/*---------------------------------------------------------------------------*
    NNS_G3dInitAnmObj

    pAnmObjをpResAnm, pResMdl用に初期化します。

    NOTICE:
    pAnmObjは最低、NNS_G3dAnmObjCalcSizeRequired(pResAnm, pResMdl)のサイズを
    持っている必要がある。

 * @param	pAnmObj		アニメＯＢＪポインタのポインタ
 * @param	pResAnm		アニメリソース
 *
 * @retval  none
 *
 *---------------------------------------------------------------------------*/
static void
CSTM_NNS_G3dAnmObjInit(NNSG3dAnmObj* pAnmObj,
                  void* pResAnm)
{
    // プログラマが定義するアニメーションの場合リソースがない場合もあるが、
    // その場合はヘッダ部分だけを偽装して入れてしまえばよい。
    const NNSG3dResAnmHeader* hdr;
    u32 i;

    pAnmObj->frame = 0;
    pAnmObj->resAnm = (void*)pResAnm;

    // アニメーション関数の設定がいる。
    // これはcategory1によって決定される
    pAnmObj->next = NULL;
    pAnmObj->priority = 127;
    pAnmObj->ratio = FX32_ONE;
    pAnmObj->resTex = NULL;

    hdr = (const NNSG3dResAnmHeader*)pResAnm;

    CSTM_NNSi_G3dAnmObjInitNsBta(pAnmObj, pResAnm);
}